/** 
 * Project Name:tinysql 
 * File Name:PlusClassUtil.java 
 * Package Name:com.wdy.golden.tinysql.plus.util 
 * Date:2021年4月26日下午5:19:13 
 * 
*/  
package com.wdy.golden.tinysql.plus.util;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.wdy.golden.tinysql.constant.TinysqlConstants;
import com.wdy.golden.tinysql.plus.annotation.TinyColumn;
import com.wdy.golden.tinysql.plus.annotation.TinyIgnore;
import com.wdy.golden.tinysql.plus.annotation.TinyTable;
import com.wdy.golden.tinysql.util.ReflectionUtil;
import com.wdy.golden.tinysql.util.StringUtil;

/** 
 * ClassName:PlusClassUtil <br/> 
 * Function: TODO ADD FUNCTION. <br/> 
 * Reason:   TODO ADD REASON. <br/> 
 * Date:     2021年4月26日 下午5:19:13 <br/> 
 * @author   DongYe_Wu 
 * @version
 * @see       
 */
public class PlusClassUtil {
	
	public static String getTableName(Class<?> clazz) {
		if(clazz.isAnnotationPresent(TinyTable.class)) {
			TinyTable tinyTable = clazz.getAnnotation(TinyTable.class);
			return tinyTable.name();
		}else {
			return clazz.getSimpleName();
		}
	}
	
	public static String getColumnName(Class<?> clazz, String fieldName) {
		Field[] fields = clazz.getDeclaredFields();
		if(fields!=null && fields.length>0) {
			for(Field field : fields) {
				if(StringUtil.equals(field.getName(), fieldName)) {
					if(field.isAnnotationPresent(TinyColumn.class)) {
						TinyColumn tinyColumn = field.getAnnotation(TinyColumn.class);
						return tinyColumn.name();
					}else {
						return field.getName();
					}
				}
			}
		}
		return null;
	}
	
	public static String getIdFieldName(Class<?> clazz) {
		Field[] fields = clazz.getDeclaredFields();
		if(fields!=null && fields.length>0) {
			for(Field field : fields) {
				if(field.isAnnotationPresent(TinyColumn.class)) {
					TinyColumn tinyColumn = field.getAnnotation(TinyColumn.class);
					if(tinyColumn.id()) {
						return field.getName();
					}
				}
			}
		}
		return TinysqlConstants.DEFAULT_ID_FIELD_NAME;
	}
	
	public static String getIdColumnName(Class<?> clazz) {
		Field[] fields = clazz.getDeclaredFields();
		if(fields!=null && fields.length>0) {
			for(Field field : fields) {
				if(field.isAnnotationPresent(TinyColumn.class)) {
					TinyColumn tinyColumn = field.getAnnotation(TinyColumn.class);
					if(tinyColumn.id()) {
						return tinyColumn.name();
					}
				}
			}
		}
		return TinysqlConstants.DEFAULT_ID_COLUMN_NAME;
	}
	
	public static String getColumns(Class<?>  clazz) {
		List<String> columns = null;
		Field[] fields = clazz.getDeclaredFields();
		if(fields!=null && fields.length>0) {
			columns = new ArrayList<String>();
			for(Field field : fields) {
				if(field.isAnnotationPresent(TinyIgnore.class)|| Modifier.isStatic(field.getModifiers())) {
					continue;
				}
				if(field.isAnnotationPresent(TinyColumn.class)) {
					TinyColumn tinyColumn = field.getAnnotation(TinyColumn.class);
					columns.add(tinyColumn.name());
				}else {
					columns.add(field.getName());
				}
			}
		}
		if(columns!=null && columns.size()>0) {
			return StringUtil.join(columns, TinysqlConstants.COMMA);
		}else {
			return TinysqlConstants.ASTERISK;
		}
	}
	
	public static String getValueFields(Class<?>  clazz) {
		List<String> columnValues = null;
		Field[] fields = clazz.getDeclaredFields();
		if(fields!=null && fields.length>0) {
			columnValues = new ArrayList<String>();
			for(Field field : fields) {
				if(field.isAnnotationPresent(TinyIgnore.class)|| Modifier.isStatic(field.getModifiers())) {
					continue;
				}
				columnValues.add(TinysqlConstants.COLON+field.getName());
			}
		}
		if(columnValues!=null && columnValues.size()>0) {
			return StringUtil.join(columnValues, TinysqlConstants.COMMA);
		}
		return null;
	}
	
	public static String getValueFields(Class<?>  clazz, String sequenceNextVal) {
		List<String> columnValues = null;
		Field[] fields = clazz.getDeclaredFields();
		if(fields!=null && fields.length>0) {
			columnValues = new ArrayList<String>();
			for(Field field : fields) {
				if(field.isAnnotationPresent(TinyIgnore.class)|| Modifier.isStatic(field.getModifiers())) {
					continue;
				}
				if(field.isAnnotationPresent(TinyColumn.class)) {
					TinyColumn tinyColumn = field.getAnnotation(TinyColumn.class);
					if(tinyColumn.id() && StringUtil.equals(tinyColumn.idGenerator(), TinysqlConstants.ID_GENETATOR_SEQUENCE)) {
						columnValues.add(sequenceNextVal);
					}else {
						columnValues.add(TinysqlConstants.COLON+field.getName());
					}
				}else {
					columnValues.add(TinysqlConstants.COLON+field.getName());
				}
			}
		}
		if(columnValues!=null && columnValues.size()>0) {
			return StringUtil.join(columnValues, TinysqlConstants.COMMA);
		}
		return null;
	}
	
	public static String getSetAll(Class<?>  clazz) {
		List<String> setColumns = null;
		Field[] fields = clazz.getDeclaredFields();
		if(fields!=null && fields.length>0) {
			setColumns = new ArrayList<String>();
			for(Field field : fields) {
				if(field.isAnnotationPresent(TinyIgnore.class)|| Modifier.isStatic(field.getModifiers())) {
					continue;
				}
				if(field.isAnnotationPresent(TinyColumn.class)) {
					TinyColumn tinyColumn = field.getAnnotation(TinyColumn.class);
					if(!tinyColumn.id()) {
						setColumns.add(tinyColumn.name()+TinysqlConstants.NAMED_PARAMETER_SYMBOL+field.getName());
					}
				}else {
					if(!StringUtil.equalsIgnoreCase(field.getName(), TinysqlConstants.DEFAULT_ID_FIELD_NAME)) {
						setColumns.add(field.getName()+TinysqlConstants.NAMED_PARAMETER_SYMBOL+field.getName());
					}
				}
			}
		}
		if(setColumns!=null && setColumns.size()>0) {
			return StringUtil.join(setColumns, TinysqlConstants.COMMA);
		}
		return null;
	}
	
	public static Map<String,Object> getEntityMap(Field[] fields, Object entity){
		Map<String,Object> entMap = null;
		if(fields!=null && fields.length>0) {
			entMap = new HashMap<String,Object>();
			for(Field field : fields) {
				if(Modifier.isStatic(field.getModifiers())) {
					continue;
				}
				try {
					entMap.put(
							field.getName(), 
							ReflectionUtil.invokeMethod(
									field.getType(), 
									StringUtil.underlineToGetMethodName(field.getName()), 
									entity
							)
					);
				} catch (NoSuchMethodException | SecurityException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
					e.printStackTrace();
				}
			}
		}
		return entMap;
	}
	
	public static Class<?> getInterfaceGenericClass(Class<?> interfaceType, Class<?> c) {
		Type[] types = interfaceType.getGenericInterfaces();
		Class<?>[] interfaceClasses = interfaceType.getInterfaces();
		if(types!=null && types.length>0) {
			for(int i=0;i<types.length;i++) {
				Type genericInterfaceType = types[i];
				if(interfaceClasses[i]==c) {
					if (genericInterfaceType instanceof ParameterizedType) {
						ParameterizedType parameterizedType = (ParameterizedType)genericInterfaceType;
						Type actualType = parameterizedType.getActualTypeArguments()[0];
						return checkType(actualType, 0);
					}
				}
			}
		}
		return null;
	}
	
    private static Class<?> checkType(Type type, int index) {
        if (type instanceof Class<?>) {
            return (Class<?>) type;
        } else if (type instanceof ParameterizedType) {
            ParameterizedType pt = (ParameterizedType) type;
            Type t = pt.getActualTypeArguments()[index];
            return checkType(t, index);
        } else {
            String className = type == null ? "null" : type.getClass().getName();
            throw new IllegalArgumentException("Expected a Class, ParameterizedType" + ", but <" + type + "> is of type " + className);
        }
    }
}
